package elms

import (
	"net/http"

	"github.com/traefik/traefik/log"
	"github.com/unrolled/render"
	"github.com/vulcand/oxy/utils"
	"net"
)

type Error struct {
	Code
	Request string        `json:"request,omitempty"`
	Params  []interface{} `json:"params,omitempty"`
	Message string        `json:"error_description,omitempty"`
}

func NewError(code Code, params ...interface{}) Error {
	return Error{
		Code:   code,
		Params: params,
	}
}

type Code struct {
	HttpStatus int    `json:"-"`
	Code       int    `json:"error_code,omitempty"`
	Error      string `json:"error,omitempty"`
}

var (
	ServiceUnavailable    = Code{http.StatusServiceUnavailable, 10002, "temporarily_unavailable"}
	PermisstonDenied      = Code{http.StatusForbidden, 10005, "access_denied"}
	NotFound              = Code{http.StatusNotFound, 10020, "not_found"}
	TokenError            = Code{http.StatusUnauthorized, 21336, "invalid_token"}
	RequestTimeout        = Code{http.StatusGatewayTimeout, 21802, "gateway_timeout"}
	PaymentRequired       = Code{http.StatusPaymentRequired, 0, "payment_required"}
	InvalidRequest        = Code{http.StatusOK, 21323, "invalid_request"}
	InvalidParameter      = Code{http.StatusOK, 10017, "invalid_parameter"}
	MissRequiredParameter = Code{http.StatusOK, 10016, "miss_required_parameter"}
	InternalError         = Code{http.StatusInternalServerError, 10001, "internal_error"}
)

var defaultRender = render.New(render.Options{
	Directory: "nowhere",
})

type LoadBalancerErrorHandler struct {
}

func (e *LoadBalancerErrorHandler) ServeHTTP(w http.ResponseWriter, r *http.Request, err error) {
	if e, ok := err.(net.Error); ok {
		if e.Timeout() {
			ErrorHandler(w, r, NewError(RequestTimeout))
			return
		}
	}
	ErrorHandler(w, r, NewError(ServiceUnavailable))
}

func init() {
	utils.DefaultHandler = &LoadBalancerErrorHandler{}
}

func ErrorHandler(w http.ResponseWriter, r *http.Request, error Error) {
	error.Request = r.URL.Path
	log.Debugf("request %v error: %v", r.URL.Path, error.Error)
	defaultRender.JSON(w, error.HttpStatus, error)
}

func TokenErrorHandler(w http.ResponseWriter, r *http.Request) {
	ErrorHandler(w, r, NewError(TokenError))
}

func NotFoundHandler(w http.ResponseWriter, r *http.Request) {
	ErrorHandler(w, r, NewError(NotFound))
}
